package cn.schoolwow.quickdao.module.database.dql.condition.flow.set;

import cn.schoolwow.quickdao.domain.QuickDAOConfig;
import cn.schoolwow.quickdao.domain.entity.Entity;
import cn.schoolwow.quickdao.domain.entity.Property;
import cn.schoolwow.quickdao.module.database.dql.parent.domain.QueryContext;
import cn.schoolwow.quickdao.module.database.dql.subCondition.domain.SubQueryOption;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;

import java.util.List;

public class SetQueryColumnListFlow implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        setAddColumnFlag(flowContext);
        handleColumnList(flowContext);
        setColumnFragment(flowContext);
    }

    @Override
    public String name() {
        return "设置查询列片段";
    }

    private void setAddColumnFlag(FlowContext flowContext){
        QueryContext queryContext = (QueryContext) flowContext.checkData("queryContext");
        if(!queryContext.queryOption.queryColumnOption.columnList.isEmpty()){
            flowContext.putTemporaryData("addColumnFlag", true);
            return;
        }
        for(SubQueryOption subQueryOption:queryContext.queryOption.subQueryOptionList){
            if(!subQueryOption.subQueryColumnOption.columnList.isEmpty()){
                flowContext.putTemporaryData("addColumnFlag", true);
                return;
            }
        }
        flowContext.putTemporaryData("addColumnFlag", false);
    }

    private void handleColumnList(FlowContext flowContext){
        QueryContext queryContext = (QueryContext) flowContext.checkData("queryContext");
        Boolean addColumnFlag = (Boolean) flowContext.checkData("addColumnFlag");

        handleExcludeColumn(queryContext.queryOption.queryColumnOption.columnList, queryContext.queryOption.queryColumnOption.excludeColumnList, queryContext.queryOption.queryTableOption.entity, addColumnFlag);
        if(queryContext.queryOption.queryColumnOption.compositeField){
            for(SubQueryOption subQueryOption:queryContext.queryOption.subQueryOptionList){
                handleExcludeColumn(subQueryOption.subQueryColumnOption.columnList, subQueryOption.subQueryColumnOption.excludeColumnList, subQueryOption.subQueryTableOption.entity, addColumnFlag);
            }
        }

        queryContext.selectParameters.addAll(queryContext.queryOption.queryColumnOption.columnParameterList);
    }

    private void setColumnFragment(FlowContext flowContext){
        QueryContext queryContext = (QueryContext) flowContext.checkData("queryContext");
        Boolean addColumnFlag = (Boolean) flowContext.checkData("addColumnFlag");

        StringBuilder sqlBuilder = new StringBuilder();
        //拼接主表字段
        sqlBuilder.append(concatColumnFragment(queryContext.queryOption.queryTableOption.entity, queryContext.queryOption.queryColumnOption.columnList, queryContext.queryOption.queryTableOption.tableAliasName, flowContext));
        if(addColumnFlag||queryContext.queryOption.queryColumnOption.compositeField){
            for(SubQueryOption subQueryOption:queryContext.queryOption.subQueryOptionList){
                sqlBuilder.append(concatColumnFragment(subQueryOption.subQueryTableOption.entity, subQueryOption.subQueryColumnOption.columnList, subQueryOption.subQueryTableOption.tableAliasName, flowContext));
            }
        }
        sqlBuilder.deleteCharAt(0);
        queryContext.select = "select " + queryContext.queryOption.queryColumnOption.distinct + sqlBuilder.toString();
    }

    private void handleExcludeColumn(List<String> columnList, List<String> excludeColumnList, Entity entity, Boolean addColumnFlag){
        if(!addColumnFlag&&columnList.isEmpty()){
            for(Property property:entity.properties){
                columnList.add(property.column);
            }
        }
        for(String excludeColumn:excludeColumnList){
            Property property = entity.getPropertyByFieldNameOrColumnName(excludeColumn);
            if(null==property){
                columnList.remove(excludeColumn);
            }else{
                columnList.remove(property.column);
                columnList.remove(property.name);
                //应对addTableColumn方法
                columnList.remove(property.column + " " + property.name);
            }
        }
    }

    private String concatColumnFragment(Entity entity, List<String> columnList, String tableAliasName, FlowContext flowContext){
        QuickDAOConfig quickDAOConfig = flowContext.checkInstanceData(QuickDAOConfig.class);
        boolean addColumnAliasName = (boolean) flowContext.checkData("addColumnAliasName");

        StringBuilder sqlBuilder = new StringBuilder();
        for(String column:columnList){
            sqlBuilder.append(",");
            if(null==entity){
                sqlBuilder.append(column);
                continue;
            }
            String columnName = column.contains(" ")?column.substring(0, column.indexOf(" ")):null;
            Property property = entity.getPropertyByFieldNameOrColumnName(null!=columnName?columnName:column);
            if(null==property){
                sqlBuilder.append(column);
                continue;
            }
            //用户自定义列包含空格的时候
            if(null!=columnName){
                sqlBuilder.append(tableAliasName+"."+quickDAOConfig.databaseContext.databaseProvider.escape(property.column)+" "+column.substring(columnName.length()+1));
                continue;
            }
            if(addColumnAliasName){
                sqlBuilder.append(tableAliasName + "." + quickDAOConfig.databaseContext.databaseProvider.escape(property.column)
                        + " as " + tableAliasName + "_" +property.column);
            }else{
                sqlBuilder.append(quickDAOConfig.databaseContext.databaseProvider.escape(property.column));
                if(null!=property.name&&!property.column.equals(property.name)){
                    sqlBuilder.append(" as "+quickDAOConfig.databaseContext.databaseProvider.escape(property.name));
                }
            }
        }
        return sqlBuilder.toString();
    }
}
